﻿using System;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Xenta.Utils;

namespace Xenta.Attributes
{
    /// <summary>
    /// Represents the attribute, which allows to secure an action 
    /// by checking if access context is authenticated.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,
        Inherited = true, AllowMultiple = false)]
    public sealed class AuthenticateAttribute : AuthorizeAttribute
    {
        /// <summary>
        /// Performs the authorization checks.
        /// </summary>
        /// <param name="httpCtx">
        /// The HTTP context, which encapsulates all 
        /// HTTP-specific information about
        /// an individual HTTP request.
        /// </param>
        /// <returns>
        /// true if the user is authorized; otherwise, false.
        /// </returns>
        protected override bool AuthorizeCore(HttpContextBase httpCtx)
        {
            if(!base.AuthorizeCore(httpCtx))
                return false;
            return httpCtx.Svc().IsAuthenticated;
        }
    }

    /// <summary>
    /// Represents the attribute which allows 
    /// to secure a controller action.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,
        Inherited = true, AllowMultiple = false)]
    public sealed class HasPermissionAttribute : FilterAttribute,
        IAuthorizationFilter
    {
        #region Fields

        private readonly string[] _permissions;

        #endregion

        #region Ctors

        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        /// <param name="permissions">The collection of the required permissions.</param>
        public HasPermissionAttribute(params string[] permissions)
        {
            _permissions = permissions;
            IsStrong = true;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Sets the required permissions.
        /// </summary>
        public string[] Permissions
        {
            get
            {
                return _permissions;
            }
        }

        /// <summary>
        /// Gets or sets a value, indicates if one or 
        /// all condition should be satisfied.
        /// </summary>
        public bool IsStrong
        {
            get;
            set;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Performs the authorization checks..
        /// </summary>
        /// <param name="filterContext">The filter context.</param>
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            if(Permissions == null || !Permissions.Any())
                return;

            var svc = filterContext.HttpContext.Svc();
            if(!svc.IsAuthenticated)
                filterContext.Result = new HttpUnauthorizedResult();
            if(!Permissions.Any(svc.HasPermission))
                filterContext.Result = new HttpUnauthorizedResult();
            if(IsStrong && !Permissions.All(svc.HasPermission))
                filterContext.Result = new HttpUnauthorizedResult();
        }

        #endregion
    }

    /// <summary>
    /// Represents the attribute which allows 
    /// to secure a controller action.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,
        Inherited = true, AllowMultiple = false)]
    public sealed class InRoleAttribute : FilterAttribute,
        IAuthorizationFilter
    {
        #region Fields

        private readonly string[] _roles;

        #endregion

        #region Ctors

        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        /// <param name="roles">The collection of the required roles.</param>
        public InRoleAttribute(params string[] roles)
        {
            _roles = roles;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Sets the required roles.
        /// </summary>
        public string[] Roles
        {
            get
            {
                return _roles;
            }
        }

        /// <summary>
        /// Gets or sets a value, indicates if one or 
        /// all condition should be satisfied.
        /// </summary>
        public bool IsStrong
        {
            get;
            set;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Performs the authorization checks..
        /// </summary>
        /// <param name="filterContext">The filter context.</param>
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            if(Roles == null || !Roles.Any())
                return;

            var svc = filterContext.HttpContext.Svc();
            if(!svc.IsAuthenticated)
                filterContext.Result = new HttpUnauthorizedResult();
            if(!Roles.Any(svc.InRole))
                filterContext.Result = new HttpUnauthorizedResult();
            if(IsStrong && !Roles.All(svc.InRole))
                filterContext.Result = new HttpUnauthorizedResult();
        }

        #endregion
    }
}